package com.ozo.easy.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ozo.easy.common.auth.UserLoginHelper;
import com.ozo.easy.common.model.*;
import com.ozo.easy.common.util.SortUtil;
import com.ozo.easy.common.exception.ServiceException;
import com.ozo.easy.entity.SysRoleMenu;
import com.ozo.easy.entity.SysUserRole;
import com.ozo.easy.exception.ServiceExceptionEnum;
import com.ozo.easy.mapper.SysRoleMenuMapper;
import com.ozo.easy.mapper.SysUserRoleMapper;
import com.ozo.easy.pojo.vo.SysMenuDetailVO;
import com.ozo.easy.entity.SysMenu;
import com.ozo.easy.mapper.SysMenuMapper;
import com.ozo.easy.pojo.dto.SysMenuSaveDTO;
import com.ozo.easy.pojo.dto.SysMenuQueryDTO;
import com.ozo.easy.pojo.vo.SysMenuVO;
import com.ozo.easy.service.ISysMenuService;
import com.ozo.easy.pojo.vo.SysDictDataVO;
import com.ozo.easy.service.ISysDictTypeService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单 服务实现类
 *
 * @author ozo
 * @version 1.0
 * @date 2025-02-14 17:13:43
 */
@RequiredArgsConstructor
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    private final ISysDictTypeService sysDictTypeService;

    private final SysUserRoleMapper sysUserRoleMapper;

    private final SysRoleMenuMapper sysRoleMenuMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(SysMenuSaveDTO saveDTO) {
        SysMenu sysMenu = BeanUtil.copyProperties(saveDTO, SysMenu.class);
        sysMenu.setEnableFlag(true);
        baseMapper.insert(sysMenu);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void remove(BaseBatchDTO<Long> batchDTO) {
        baseMapper.deleteBatchIds(batchDTO.getIdList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(SysMenuSaveDTO saveDTO) {
        if (saveDTO.getId().equals(saveDTO.getParentId())) {
            throw new ServiceException(ServiceExceptionEnum.PARENT_NOT_ONESELF);
        }
        SysMenu sysMenu = BeanUtil.copyProperties(saveDTO, SysMenu.class);
        baseMapper.updateById(sysMenu);
    }

    @Override
    public List<SysMenuVO> list(SysMenuQueryDTO queryDTO) {
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        // 排序
        String order = queryDTO.getOrder();
        if (StrUtil.isBlank(order)) {
            queryWrapper.lambda().orderByAsc(SysMenu::getOrderNum);
        } else {
            SortUtil.setSortCondition(queryWrapper, queryDTO.getProp(), order);
        }
        // 条件
        queryWrapper.lambda()
                .like(StrUtil.isNotBlank(queryDTO.getTitle()), SysMenu::getTitle, queryDTO.getTitle())
                .eq(StrUtil.isNotBlank(queryDTO.getType()), SysMenu::getType, queryDTO.getType());
        List<SysMenu> recordList = baseMapper.selectList(queryWrapper);

        List<SysMenuVO> recordVOList = BeanUtil.copyToList(recordList, SysMenuVO.class);

        if (CollUtil.isNotEmpty(recordVOList)) {
            List<Long> idList = recordVOList.stream().filter(e -> e.getParentId() != null).map(SysMenuVO::getParentId).collect(Collectors.toList());
            Map<Long, String> menuMap = new HashMap<>();
            if (CollUtil.isNotEmpty(idList)) {
                baseMapper.selectBatchIds(idList).forEach(e -> menuMap.put(e.getId(), e.getTitle()));
            }

            Map<String, String> typeMap = sysDictTypeService.listData("MENU_TYPE").stream().collect(Collectors.toMap(SysDictDataVO::getDictValue, SysDictDataVO::getDictItem));

            for (SysMenuVO sysMenuVO : recordVOList) {
                sysMenuVO.setTypeDesc(typeMap.get(sysMenuVO.getType()));

                List<SysMenuVO> collect = recordVOList.stream().filter(e -> sysMenuVO.getId().equals(e.getParentId())).collect(Collectors.toList());
                sysMenuVO.setParentName(menuMap.get(sysMenuVO.getParentId()));
                sysMenuVO.setChildren(collect);
            }
        }

        return recordVOList.stream().filter(e -> e.getParentId() == null).collect(Collectors.toList());
    }

    @Override
    public SysMenuDetailVO detail(Long id) {
        SysMenu sysMenu = baseMapper.selectById(id);
        if (Objects.isNull(sysMenu)) {
            throw new ServiceException(ServiceExceptionEnum.DATA_NOT_EXISTS);
        }
        SysMenuDetailVO sysMenuDetailVO = BeanUtil.copyProperties(sysMenu, SysMenuDetailVO.class);
        if (sysMenu.getParentId() != null) {
            SysMenu parentMenu = baseMapper.selectById(sysMenu.getParentId());
            sysMenuDetailVO.setParentName(parentMenu != null ? parentMenu.getTitle() : "");
        }
        return sysMenuDetailVO;
    }

    @Override
    public void enable(Long id) {
        SysMenu sysMenu = baseMapper.selectById(id);
        if (Objects.isNull(sysMenu)) {
            throw new ServiceException(ServiceExceptionEnum.DATA_NOT_EXISTS);
        }
        sysMenu.setEnableFlag(!sysMenu.getEnableFlag());
        baseMapper.updateById(sysMenu);
    }

    @Override
    public List<SysMenuVO> listAuth() {
        Long userId = UserLoginHelper.getUserId();

        List<SysMenuVO> list = new ArrayList<>();

        LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserRole::getUserId, userId);
        List<Long> roleIdList = sysUserRoleMapper.selectList(queryWrapper).stream().map(SysUserRole::getRoleId).collect(Collectors.toList());

        if (CollUtil.isEmpty(roleIdList)) {
            return list;
        }

        LambdaQueryWrapper<SysRoleMenu> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.in(SysRoleMenu::getRoleId, roleIdList);
        List<Long> menuIdList = sysRoleMenuMapper.selectList(queryWrapper1).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
        if (CollUtil.isEmpty(menuIdList)) {
            return list;
        }

        LambdaQueryWrapper<SysMenu> queryWrapper2 = new LambdaQueryWrapper<>();
        queryWrapper2.in(SysMenu::getId, menuIdList)
                .eq(SysMenu::getType, "MENU")
                .eq(SysMenu::getEnableFlag, true);
        List<SysMenu> sysMenuList = baseMapper.selectList(queryWrapper2);

        List<SysMenuVO> recordVOList = BeanUtil.copyToList(sysMenuList, SysMenuVO.class);
        if (CollUtil.isNotEmpty(recordVOList)) {
            for (SysMenuVO sysMenuVO : recordVOList) {
                List<SysMenuVO> collect = recordVOList.stream().filter(e -> sysMenuVO.getId().equals(e.getParentId())).collect(Collectors.toList());
                sysMenuVO.setChildren(collect);
            }
        }

        return recordVOList.stream().filter(e -> e.getParentId() == null).collect(Collectors.toList());
    }

}
